package com.yanx.common.utils;

import cn.hutool.extra.spring.SpringUtil;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Json工具类，基于Jackson实现
 *
 * @author gotanks
 * @version 1.4
 * @since 2020-10-20
 */
@Slf4j
public class Json_ {

    /**
     * 将对象转化成json
     *
     * @param t
     * @return
     */
    public static <T> String toJson(T t) {
        if (t instanceof String) {
            return (String) t;
        }
        try {
            return getMapper().writeValueAsString(t);
        } catch (IOException e) {
            log.error("obj to json error.\n{}", getThrowMsg(e));
        }
        return null;
    }

    /**
     * 将json转化成tree
     *
     * @param json
     * @return
     */
    public static JsonNode toTree(String json) {
        if (String_.isEmpty(json)) {
            log.warn("json string is empty!");
            return null;
        }
        try {
            return getMapper().readTree(json);
        } catch (JsonProcessingException e) {
            log.error("json to tree error.\n{}", getThrowMsg(e));
            return null;
        }
    }

    /**
     * 将json转化成bean
     *
     * @param json
     * @param valueType
     * @return
     */
    public static <T> T toBean(String json, Class<T> valueType) {
        if (String_.isEmpty(json)) {
            log.warn("json string {} is empty!", valueType);
            return null;
        }
        try {
            return getMapper().readValue(json, valueType);
        } catch (JsonProcessingException e) {
            log.error("json to obj error.\n{}", getThrowMsg(e));
            return null;
        }
    }

    /**
     * 将json转化成ArrayList<String>
     *
     * @param json
     * @return
     */
    public static List<String> toList(String json) {
        return toList(json, String.class);
    }

    /**
     * 将json转化成ArrayList
     *
     * @param json
     * @param elementClass
     * @param <T>
     * @return
     */
    public static <T> List<T> toList(String json, Class<T> elementClass) {
        return toList(json, ArrayList.class, elementClass);
    }

    /**
     * 将json转化成List
     *
     * @param json
     * @param collectionClass
     * @param elementClass
     * @return
     */
    public static <T> List<T> toList(String json, Class<? extends List> collectionClass, Class<T> elementClass) {
        if (String_.isEmpty(json)) {
            log.warn("json string is empty!");
            return null;
        }
        JavaType javaType = getMapper().getTypeFactory().constructCollectionType(collectionClass, elementClass);
        try {
            return getMapper().readValue(json, javaType);
        } catch (JsonProcessingException e) {
            log.error("json to list error.\n{}", getThrowMsg(e));
            return null;
        }
    }

    /**
     * 将json转化成HashMap<String, String>
     *
     * @param json
     * @return
     */
    public static Map<String, String> toMap(String json) {
        return toMap(json, String.class);
    }

    /**
     * 将json转化成HashMap<String, Object>
     *
     * @param json
     * @param valueClass
     * @param <V>
     * @return
     */
    public static <V> Map<String, V> toMap(String json, Class<V> valueClass) {
        return toMap(json, String.class, valueClass);
    }

    /**
     * 将json转化成HashMap
     *
     * @param json
     * @param keyClass
     * @param valueClass
     * @param <K>
     * @param <V>
     * @return
     */
    public static <K, V> Map<K, V> toMap(String json, Class<K> keyClass, Class<V> valueClass) {
        return toMap(json, HashMap.class, keyClass, valueClass);
    }

    /**
     * 将json转化成Map
     *
     * @param json
     * @param mapClass
     * @param keyClass
     * @param valueClass
     * @return
     */
    public static <K, V> Map<K, V> toMap(String json, Class<? extends Map> mapClass, Class<K> keyClass, Class<V> valueClass) {
        if (String_.isEmpty(json)) {
            log.warn("json string is empty!");
            return null;
        }
        JavaType javaType = getMapper().getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
        try {
            return getMapper().readValue(json, javaType);
        } catch (JsonProcessingException e) {
            log.error("json to map error.\n{}", getThrowMsg(e));
            return null;
        }
    }

    /**
     * 将json转化成指定类型的对象
     *
     * @param json
     * @param typeReference
     * @param <T>
     * @return
     */
    public static <T> T to(String json, TypeReference<T> typeReference) {
        if (String_.isBlank(json) || typeReference == null) {
            return null;
        }
        try {
            return getMapper().readValue(json, typeReference);
        } catch (JsonProcessingException e) {
            log.error("json convert error.\n{}", getThrowMsg(e));
            return null;
        }
    }

    /**
     * 将json转化成xml<String>
     *
     * @param json
     * @return
     */
    public static String toXml(String json) {
        try {
            JsonNode jsonNode = getMapper().readTree(json);
            String xmlStr = getXmlMapper().writeValueAsString(jsonNode);
            xmlStr = String_.subBetween(xmlStr, "<ObjectNode>", "</ObjectNode>");
            return xmlStr;
        } catch (JsonProcessingException e) {
            log.error("json to xml error.\n{}", getThrowMsg(e));
            return null;
        }
    }

    /**
     * 将xml转化成json<String>
     *
     * @param xml
     * @return
     */
    public static String fromXml(String xml) {
        try {
            if (String_.contains(xml, "?>")) {
                xml = String_.subAfter(xml, "?>", false);
            }
            xml = String_.join("", "<gotanks>", xml, "</gotanks>");
            JsonNode jsonNode = getXmlMapper().readTree(xml);
            final String jsonStr = getMapper().writeValueAsString(jsonNode);
            return jsonStr;
        } catch (JsonProcessingException e) {
            log.error("xml to json error.\n{}", getThrowMsg(e));
            return null;
        }
    }

    /**
     * 将源对象转为一个具有相似属性的目标对象（效率低）
     *
     * @param srcObj
     * @param targetObjClazz
     * @return
     * @throws JsonParseException
     * @throws JsonMappingException
     * @throws JsonProcessingException
     * @throws IOException
     */
    public static <T> T copyProperties(Object srcObj, Class<T> targetObjClazz) {
        return toBean(toJson(srcObj), targetObjClazz);
    }

    // ################################################################################################################

    /**
     * 禁止调用无参构造
     */
    private Json_() {

    }

    /**
     * 使用ThreadLocal创建对象，防止出现线程安全问题
     */
    private final static Jackson2ObjectMapperBuilder builder = SpringUtil.getBean(Jackson2ObjectMapperBuilder.class);

    private static final ThreadLocal<ObjectMapper> OBJECT_MAPPER = ThreadLocal.withInitial(builder.createXmlMapper(false)::build);
    private static final ThreadLocal<ObjectMapper> XML_MAPPER = ThreadLocal.withInitial(XmlMapper::new);

    public static ObjectMapper getMapper() {
        return OBJECT_MAPPER.get();
    }

    public static ObjectMapper getXmlMapper() {
        return XML_MAPPER.get();
    }

    private static Object getThrowMsg(Exception e) {
//        for (StackTraceElement element : e.getStackTrace()) {
//            String str = element.toString();
//            return str;
//        }
        return e;
    }
}
